﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Genuilder.Extensibility;
using System.Text.RegularExpressions;
using Genuilder.Extensions.XamlVerifier;
using System.Runtime.Serialization;
using Genuilder.Extensibility.NRefactory;

namespace Genuilder.Extensions
{
	[DataContract]
	public class XamlVerifierExtension : IExtension
	{
		public XamlVerifierExtension()
		{
			StopAfterFirstError = false;
		}
		#region IExtension Members

		[DataMember]
		public FileQuery XamlFiles
		{
			get;
			set;
		}

		[DataMember]
		public FileQuery CodeFiles
		{
			get;
			set;
		}

		[DataMember]
		public bool AutoCorrect
		{
			get;
			set;
		}

		[DataMember]
		public bool StopAfterFirstError
		{
			get;
			set;
		}

		public void Execute(ExtensionContext extensionContext)
		{
			var xamlFiles = XamlFiles ?? new FileQuery().SelectInThisDirectory(true).All().ToQuery();
			var codeFiles = CodeFiles ?? new FileQuery().SelectInThisDirectory(true).All().ToQuery();

			var xamlFilesByName = extensionContext.GenItems
				.GetByQuery(xamlFiles)
				.Where(i => i.SourceType == SourceType.Page)
				.ToDictionary(o => o.Name);

			if(xamlFilesByName.Count == 0)
				return;

			XamlVerifierEvaluator evaluator = new XamlVerifierEvaluator();
			evaluator.XamlFiles.AddRange(xamlFilesByName.Keys);

			foreach(var compilationUnitExtension in extensionContext.GenItems
				.GetByQuery(codeFiles)
				.Where(i => i.SourceType == SourceType.Compile)
				.Select(i => i.GetExtension<CompilationUnitExtension>()))
			{
				compilationUnitExtension.ParseMethodBodies = false;
				if(compilationUnitExtension.CompilationUnit != null)
					evaluator.CodeFiles.Add(compilationUnitExtension.CompilationUnit);
			}

			XamlCorrector corrector = AutoCorrect ? new XamlCorrector()
			{
				Evaluator = evaluator
			} : null;

			var errors = corrector == null ? evaluator.AllErrors() : corrector.AllErrors();

			foreach(var error in errors)
			{
				if(AutoCorrect)
					continue;

				var item = xamlFilesByName[error.File];
				item.Logger.Error(ToString(error), error.Location);

				if(StopAfterFirstError)
				{
					break;
				}
			}

			if(corrector != null)
				corrector.SaveCorrections();
		}

		private string ToString(XamlVerifierError error)
		{
			var propertyError = error as XamlVerifierPropertyError;
			if(propertyError != null)
			{
				return propertyError.PropertyName + " does not exist in " + propertyError.ClassName + Suggestion(error);
			}
			var classError = error as XamlVerifierTypeError;
			if(classError != null)
			{
				return classError.TypeName + " does not exist" + Suggestion(error);
			}
			return error.ToString();
		}

		private string Suggestion(XamlVerifierError error)
		{
			if(error.Suggestion == null)
				return "";
			return ", do you mean " + error.Suggestion + " ?";
		}

		#endregion
	}
}
